//
// Created by songpingwang on 25-7-4.
//

#ifndef UDATABASE_INL
#define UDATABASE_INL
#include "UDataBase.h"
#include <iostream>
#include <sstream>




template<NDFrame::Field field>
std::string NDFrame::join(UDataBase::VecItemPtr &in_ptr, const std::string &Char_) {
    if (in_ptr.empty() || Char_.size() >= 2) {
        return {};
    }

    std::basic_ostringstream<char> oss;
    for (size_t i = 0; i < in_ptr.size(); ++i) {
        if (i != 0 && !Char_.empty()) {
            oss << Char_;
        }
        oss << getTextRef<field>(*in_ptr[i]);
    }
    return oss.str();
}


inline bool NDFrame::UDataBase::ptr2_xyxy(
	VecItemPtr& inout_ptr,
	const std::function<bool(const DataItem&)>& condition) {
	if (inout_ptr.empty()) return false;

	VecItemPtr filtered_pointers;
	filtered_pointers.reserve(inout_ptr.size());

	for (auto& index : inout_ptr) {
		if (condition(*index)) {
			filtered_pointers.push_back(index);
		}
	}

	inout_ptr = std::move(filtered_pointers);
	return !inout_ptr.empty();
}






template<NDFrame::Field field>
bool NDFrame::UDataBase::ptr2_reg_impl_(VecItemPtr &inout_ptr, const VecRE2Ptr &regex_) {
    VecItemPtr filtered_pointers;
    filtered_pointers.reserve(inout_ptr.size());

    for (auto& item_ptr : inout_ptr) {
        const std::string& field_value = getTextRefConst<field>(*item_ptr);
        for (const auto& reg : regex_) {
        	if (RE2::PartialMatch(field_value, *reg)) {
        		filtered_pointers.push_back(item_ptr);
        		break;
        	}
        }
    }

    inout_ptr = std::move(filtered_pointers);
    return !inout_ptr.empty();
}


template<NDFrame::Field field>
bool NDFrame::UDataBase::ptr2_reg_impl_with_set(VecItemPtr &inout_ptr, const RE2::Set& regex_set) {
	VecItemPtr filtered_pointers;
	filtered_pointers.reserve(inout_ptr.size());

	for (const auto& item_ptr : inout_ptr) {
		const std::string& field_value = getTextRefConst<field>(*item_ptr);
		if (regex_set.Match(field_value, nullptr)) {
			filtered_pointers.push_back(item_ptr);
		}
	}

	inout_ptr = std::move(filtered_pointers);
	return !inout_ptr.empty();
}



template<NDFrame::Field field>
bool NDFrame::UDataBase::ptr2_reg_len_impl(
        VecItemPtr& inout_ptr,
        const VecRE2Ptr& regex_, const int len,
	    const std::function<bool(size_t, size_t)>& compare) {

	if (inout_ptr.empty()) return false;

	VecItemPtr filtered_pointers;
	filtered_pointers.reserve(inout_ptr.size());

	for (auto& item_ptr : inout_ptr) {
		const std::string& field_value = getTextRefConst<field>(*item_ptr);
		if (compare(field_value.size(), len)) {
			for (const auto& reg : regex_) {
				if (RE2::PartialMatch(field_value, *reg)) {
					filtered_pointers.push_back(item_ptr);
					break;
				}
			}
		}
	}
	inout_ptr = std::move(filtered_pointers);
	return !inout_ptr.empty();
}



template<NDFrame::Field field>
bool NDFrame::UDataBase::ptr2_reg_condition(
        VecItemPtr& inout_ptr,
        const VecRE2Ptr& regex_,
	    const std::function<bool(const DataItem&)>& condition) {

	if (inout_ptr.empty()) return false;

	VecItemPtr filtered_pointers;
	filtered_pointers.reserve(inout_ptr.size());

	for (auto& item_ptr : inout_ptr) {
		if (condition(*item_ptr)) {
			const std::string& field_value = getTextRefConst<field>(*item_ptr);
			for (const auto& reg : regex_) {
				if (RE2::PartialMatch(field_value, *reg)) {
					filtered_pointers.push_back(item_ptr);
					break;
				}
			}
		}
	}

	inout_ptr = std::move(filtered_pointers);
	return !inout_ptr.empty();
}


inline size_t NDFrame::get_visual_width(const std::string& str) {
	size_t width = 0;
	for (size_t i = 0; i < str.size(); ) {
		const unsigned char c = str[i];
		if (c < 0x80) {                 // 0xxxxxxx: 1-byte ASCII
			width += 1;
			i += 1;
		} else if ((c & 0xE0) == 0xC0) { // 110xxxxx: 2-byte UTF-8 sequence
			width += 2;
			i += 2;
		} else if ((c & 0xF0) == 0xE0) { // 1110xxxx: 3-byte UTF-8 sequence (常见中文字符)
			width += 2;
			i += 3;
		} else if ((c & 0xF8) == 0xF0) { // 11110xxx: 4-byte UTF-8 sequence
			width += 2;
			i += 4;
		} else {
			width += 1;
			i += 1;
		}
	}
	return width;
}


inline void NDFrame::print_separator(std::ostream &os, const std::vector<size_t> &widths, const char separator) {
	os << '+';
	for (const size_t width: widths) {
		os << std::string(width + 2, separator) << '+';
	}
	os << std::endl;
}


inline void NDFrame::print_row(std::ostream &os, const std::vector<size_t> &widths, const std::vector<std::string> &row_data) {
	os << "| ";
	for (size_t i = 0; i < row_data.size(); ++i) {
		const std::string &cell = row_data[i];
		const size_t visual_w = get_visual_width(cell);
		const size_t padding = widths[i] > visual_w ? widths[i] - visual_w : 0;
		os << std::left << cell << std::string(padding, ' ') << " | ";
	}
	os << std::endl;
}


inline void NDFrame::format_print(const UDataBase &database) {
	if (database.empty()) {
		return;
	}

	// 1. 初始化表头和列宽
	const std::vector<std::string> headers = {
		"idx", "x0", "y0", "x1", "y1", "width", "height", "page", "flags", "text", "text_sep"
	};
	std::vector<size_t> widths;
	widths.reserve(headers.size());
	for (const auto &header: headers) {
		widths.push_back(get_visual_width(header));
	}

	// 2. 遍历数据，计算所有行的字符串表示，并更新最大列宽
	const size_t data_size = database.size();
	const DataItem *item_ptr = database.getItemPtr();
	std::vector<std::vector<std::string> > all_rows_data;
	all_rows_data.reserve(data_size);

	for (size_t i = 0; i < data_size; ++i) {
		all_rows_data.push_back({
			std::to_string(item_ptr[i].idx),
			std::to_string(item_ptr[i].x0),
			std::to_string(item_ptr[i].y0),
			std::to_string(item_ptr[i].x1),
			std::to_string(item_ptr[i].y1),
			std::to_string(item_ptr[i].width),
			std::to_string(item_ptr[i].height),
			std::to_string(item_ptr[i].page),
			std::to_string(item_ptr[i].flags),
			item_ptr[i].text,
			item_ptr[i].text_sep
		});
		const auto &current_row = all_rows_data.back();
		for (size_t j = 0; j < headers.size(); ++j) {
			widths[j] = std::max(widths[j], get_visual_width(current_row[j]));
		}
	}

	// 3. 设置输出环境并打印
	std::ostringstream oss;
#if _WIN32
	// 在Windows上， <windows.h> 的 SetConsoleOutputCP
	std::cout.imbue(std::locale("zh_CN"));
#else
	oss.imbue(std::locale("zh_CN.UTF-8"));
#endif

	// 打印表头
	print_separator(oss, widths, '-');
	print_row(oss, widths, headers);
	print_separator(oss, widths, '=');

	// 打印所有数据行
	for (const auto &row_data: all_rows_data) {
		print_row(oss, widths, row_data);
	}
	print_separator(oss, widths, '-');
	std::cout.imbue(std::locale(""));
	std::cout << oss.str();
}


inline void NDFrame::format_print(const UDataBase *dataframe) {
	if (dataframe == nullptr || dataframe->empty()) {
		return;
	}
	format_print(*dataframe);
}


inline void NDFrame::format_print(const std::vector<DataItem *> &pointers) {
	if (pointers.empty()) {
		std::cout << "No data to display." << std::endl;
		return;
	}

	// 1. 初始化表头和列宽
	const std::vector<std::string> headers = {
		"idx", "x0", "y0", "x1", "y1", "width", "height", "page", "flags", "text", "text_sep"
	};
	std::vector<size_t> widths;
	widths.reserve(headers.size());
	for (const auto &header: headers) {
		widths.push_back(get_visual_width(header));
	}

	// 添加每行的数据，并更新最大宽度
	std::vector<std::vector<std::string> > all_rows_data;
	all_rows_data.reserve(pointers.size());
	for (const DataItem *item_ptr: pointers) {
		if (!item_ptr) { continue; }
		all_rows_data.push_back({
			std::to_string(item_ptr->idx),
			std::to_string(item_ptr->x0),
			std::to_string(item_ptr->y0),
			std::to_string(item_ptr->x1),
			std::to_string(item_ptr->y1),
			std::to_string(item_ptr->width),
			std::to_string(item_ptr->height),
			std::to_string(item_ptr->page),
			std::to_string(item_ptr->flags),
			item_ptr->text,
			item_ptr->text_sep
		});
		const auto &current_row_strings = all_rows_data.back();
		for (size_t j = 0; j < headers.size(); ++j) {
			widths[j] = std::max(widths[j], get_visual_width(current_row_strings[j]));
		}
	}

	if (all_rows_data.empty()) {
		std::cout << "No valid data to display." << std::endl;
		return;
	}

	std::ostringstream oss;
	oss.imbue(std::locale(""));

	// 打印表头
	print_separator(oss, widths, '-');
	print_row(oss, widths, headers);
	print_separator(oss, widths, '=');

	// 打印所有数据行
	for (const auto &row_data: all_rows_data) {
		print_row(oss, widths, row_data);
	}
	print_separator(oss, widths, '-');
	std::cout.imbue(std::locale(""));
	std::cout << oss.str();
}




#endif